﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace WebRamosUCWebCrawler
{
    public partial class MainForm : Form
    {
        public AddFromUrlCallback addFromUrlCallback;
        public SaveRamosToFile saveRamosToFile;
        Dictionary<string, List<string>> direcciones;
        Thread th;
        object syncObjDescarga = new object();

        /// <param name="urlDict">Diccionario con nombre y url de cada carrera (de donde se bajan los ramos)</param>
        /// <param name="addFromUrlCallback">Metodo a ejecutar cuando se solicite agregar url's</param>
        public MainForm(Dictionary<string,List<string>> urlDict)
        {
            InitializeComponent();

            direcciones = urlDict;
            
            List<string> carreras = direcciones.Keys.ToList();
            carreras.Sort();
            
            comboBoxCarreras.Items.AddRange(carreras.ToArray());
            comboBoxCarreras.SelectedIndex = 0;
        }

        private void buttonDownload_Click(object sender, EventArgs e)
        {
            if (th != null && th.IsAlive)
                throw new ThreadStateException("wtf?");
            th = new Thread(new ThreadStart(DescargarSeleccion));
            th.Start();
        }

        /// <summary>
        /// Descarga el ramo seleccionado en el combobox. Este metodo es ejecutado en un thread nuevo.
        /// </summary>
        private void DescargarSeleccion()
        {
            lock (syncObjDescarga)
            {
                this.Invoke(new Action<bool>(DescargandoControlUpdater), true); //Malditos threads >_>
                this.Invoke(new Action<string>(delegate(string s) { statusLabel1.Text = s; }), "Descargando, porfavor espere...");

                string seleccion = (string)this.Invoke(
                    new Func<object>(delegate(){ return comboBoxCarreras.SelectedItem; })); //Anonymous methods y magia para saber el item seleccionado del combobox

                int total = addFromUrlCallback.Invoke(seleccion, direcciones[seleccion]);

                this.Invoke(new Action<bool>(DescargandoControlUpdater), false); //Malditos threads >_>
                this.Invoke(new Action<string>(delegate(string s) { statusLabel1.Text = s; }), "Descargado exitosamente " + total + " ramos.");
            }
        }

        private void buttonDownloadAll_Click(object sender, EventArgs e)
        {
            //Pedir confirmacion antes de descargar todo:
            if (DialogResult.OK == 
                MessageBox.Show("Estas 100% seguro que quieres descargar TODOS los ramos de la Universidad?", "Confirmación", 
                                MessageBoxButtons.OKCancel, MessageBoxIcon.Information))
            {
                if (th != null && th.IsAlive)
                    throw new ThreadStateException("wtf?");
                th = new Thread(new ThreadStart(DescargarTodo));
                th.Start();
            }
        }

        /// <summary>
        /// Descarga todos los ramos disponibles. Este metodo es ejecutado en un thread nuevo.
        /// </summary>
        private void DescargarTodo()
        {
            lock (syncObjDescarga)
            {
                this.Invoke(new Action<bool>(DescargandoControlUpdater), true); //Malditos threads >_>
                this.Invoke(new Action<string>(delegate(string s) { statusLabel1.Text = s; }), "Descargando, porfavor espere...");

                int total = 0;
                foreach (KeyValuePair<string, List<string>> item in direcciones)
                {
                    this.Invoke(new Action<string>(delegate(string s) { statusLabel1.Text = s; }), "Descargando ramos de " + item.Key + "...");
                    total += addFromUrlCallback.Invoke(item.Key, item.Value);
                }

                this.Invoke(new Action<bool>(DescargandoControlUpdater), false); //Malditos threads >_>
                this.Invoke(new Action<string>(delegate(string s) { statusLabel1.Text = s; }), "Descargado exitosamente " + total + " ramos.");
            }
        }

        /// <summary>
        /// Metodo usado por otros threads para (des)habilitar los controles, sin lanzar un feo
        /// IllegalCrossThread blaa...
        /// </summary>
        /// <param name="descargando">True para deshabilitar, false para dejarlos normal</param>
        private void DescargandoControlUpdater(bool descargando)
        {
            if (descargando)
            {
                buttonSaveFile.Enabled = false;
                buttonDB.Enabled = false;
                buttonDownload.Enabled = false;
                buttonDownloadAll.Enabled = false;
                comboBoxCarreras.Enabled = false;
                buttonAbort.Visible = true;
                progressBar1.Visible = true;
                progressBar1.Style = ProgressBarStyle.Marquee;
            }
            else
            {
                buttonSaveFile.Enabled = true;
                //buttonDB.Enabled = true;
                buttonDownload.Enabled = true;
                buttonDownloadAll.Enabled = true;
                comboBoxCarreras.Enabled = true;
                buttonAbort.Visible = false;
                progressBar1.Visible = false;
                progressBar1.Style = ProgressBarStyle.Continuous;
            }
        }

        /// <summary>
        /// Aborta la descarga matando al thread encargado.
        /// </summary>
        private void buttonAbort_Click(object sender, EventArgs e)
        {
            if (th != null && th.IsAlive)
            {
                th.Abort();
                DescargandoControlUpdater(false);
                statusLabel1.Text = "Descarga cancelada.";
            }
        }

        private void buttonSaveFile_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string file = saveFileDialog1.FileName;
                saveRamosToFile.Invoke(file);
                statusLabel1.Text = "Guardado exitosamente en archivo.";
            }
        }

        /// <summary>
        /// Insertar datos a la DB.
        /// </summary>
        private void buttonDB_Click(object sender, EventArgs e)
        {
            MessageBox.Show("No implementado!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        /// <summary>
        /// Actualizar textBox con URL.
        /// </summary>
        private void comboBoxCarreras_SelectedIndexChanged(object sender, EventArgs e)
        {
            textBoxUrl.Text = String.Join("\r\n", direcciones[(string)comboBoxCarreras.SelectedItem].ToArray());
            textBoxUrl.SelectionStart = textBoxUrl.TextLength;
            textBoxUrl.ScrollToCaret();
        }

        public void AddLogMessage(string message)
        {
            if (richTextBoxTrace.InvokeRequired)
                this.Invoke(new Action<string>(AddLogMessage), message);
            else
            {
                richTextBoxTrace.AppendText(message);
                richTextBoxTrace.Select(richTextBoxTrace.Text.Length, 0);
                richTextBoxTrace.ScrollToCaret();
            }
        }
    }
}
